using System.Net;
using System.Net.Sockets;
using System.Text;

namespace AndroidApp2
{
    /// <summary>
    /// Socket连接配置类
    /// 包含所有Socket连接相关的配置参数
    /// </summary>
    public class SocketConfig
    {
        /// <summary>
        /// 服务器地址
        /// 支持IP地址或域名
        /// 默认值：192.168.10.121
        /// </summary>
        public string ServerAddress { get; set; } = "192.168.10.121";
        
        /// <summary>
        /// 服务器端口号
        /// 有效范围：1-65535
        /// 默认值：1605
        /// </summary>
        public int ServerPort { get; set; } = 1605;
        
        /// <summary>
        /// 连接超时时间（毫秒）
        /// 超过此时间未连接成功将抛出超时异常
        /// 建议范围：3000-10000ms
        /// 默认值：5000ms（5秒）
        /// </summary>
        public int ConnectTimeoutMs { get; set; } = 5000;
        
        /// <summary>
        /// 数据接收超时时间（毫秒）
        /// 超过此时间未收到数据将触发重连机制
        /// 建议范围：10000-60000ms
        /// 默认值：30000ms（30秒）
        /// </summary>
        public int ReceiveTimeoutMs { get; set; } = 30000;
        
        /// <summary>
        /// 数据缓冲区大小（字节）
        /// 影响单次接收数据的最大长度
        /// 建议范围：512-8192字节
        /// 默认值：1024字节（1KB）
        /// </summary>
        public int BufferSize { get; set; } = 1024;
        
        /// <summary>
        /// 最大重连尝试次数
        /// 连接失败时的最大重试次数
        /// 0表示不重连，-1表示无限重连
        /// 默认值：3次
        /// </summary>
        public int MaxReconnectAttempts { get; set; } = 3;
        
        /// <summary>
        /// 重连延迟时间（毫秒）
        /// 每次重连尝试之间的等待时间
        /// 建议范围：1000-5000ms
        /// 默认值：2000ms（2秒）
        /// </summary>
        public int ReconnectDelayMs { get; set; } = 2000;
        
        /// <summary>
        /// 验证配置参数是否有效
        /// </summary>
        /// <returns>配置是否有效</returns>
        public bool IsValid()
        {
            return !string.IsNullOrWhiteSpace(ServerAddress) &&
                   ServerPort > 0 && ServerPort <= 65535 &&
                   ConnectTimeoutMs > 0 &&
                   ReceiveTimeoutMs > 0 &&
                   BufferSize > 0 &&
                   MaxReconnectAttempts >= -1 &&
                   ReconnectDelayMs >= 0;
        }
        
        /// <summary>
        /// 获取配置信息的字符串表示
        /// </summary>
        /// <returns>配置信息</returns>
        public override string ToString()
        {
            return $"Server: {ServerAddress}:{ServerPort}, " +
                   $"ConnectTimeout: {ConnectTimeoutMs}ms, " +
                   $"ReceiveTimeout: {ReceiveTimeoutMs}ms, " +
                   $"BufferSize: {BufferSize}B, " +
                   $"MaxReconnect: {MaxReconnectAttempts}, " +
                   $"ReconnectDelay: {ReconnectDelayMs}ms";
        }
    }
    
    /// <summary>
    /// Socket状态回调接口
    /// </summary>
    public interface ISocketStateCallback
    {
        void OnSocketStateChanged(bool isConnected);
        void OnSocketMessageReceived(string message);
        void OnSocketError(string error);
    }

    /// <summary>
    /// Socket客户端管理器
    /// 负责TCP Socket连接、数据收发和状态管理
    /// </summary>
    public class SocketManager : IDisposable
    {
        /// <summary>
        /// 连接配置
        /// </summary>
        private readonly SocketConfig _config;
        
        /// <summary>
        /// TCP客户端
        /// </summary>
        private TcpClient? _tcpClient;
        
        /// <summary>
        /// Socket连接状态
        /// </summary>
        private volatile bool _isConnected = false;
        
        /// <summary>
        /// 状态回调接口
        /// </summary>
        private ISocketStateCallback? _callback;
        
        /// <summary>
        /// 数据接收任务取消令牌
        /// </summary>
        private CancellationTokenSource? _cancellationTokenSource;
        
        /// <summary>
        /// 重连尝试次数
        /// </summary>
        private int _reconnectAttempts = 0;
        
        /// <summary>
        /// 线程锁
        /// </summary>
        private readonly object _lock = new object();
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="config">连接配置</param>
        public SocketManager(SocketConfig? config = null)
        {
            _config = config ?? new SocketConfig();
        }
        
        /// <summary>
        /// 设置状态回调
        /// </summary>
        /// <param name="callback">状态回调接口</param>
        public void SetCallback(ISocketStateCallback? callback)
        {
            _callback = callback;
        }
        
        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <returns>连接任务</returns>
        public async Task<bool> ConnectAsync()
        {
            lock (_lock)
            {
                if (_isConnected)
                {
                    _callback?.OnSocketError("Socket已连接，无需重复连接");
                    return true;
                }
            }

            return await ConnectWithRetryAsync();
        }
        
        /// <summary>
        /// 带重连机制的连接
        /// </summary>
        /// <returns>连接结果</returns>
        private async Task<bool> ConnectWithRetryAsync()
        {
            for (int attempt = 0; attempt <= _config.MaxReconnectAttempts; attempt++)
            {
                try
                {
                    _callback?.OnSocketMessageReceived($"开始连接Socket服务器 {_config.ServerAddress}:{_config.ServerPort} (第{attempt + 1}次尝试)");
                    
                    _tcpClient = new TcpClient();
                    _cancellationTokenSource = new CancellationTokenSource();
                    
                    // 设置连接超时
                    var connectTask = _tcpClient.ConnectAsync(IPAddress.Parse(_config.ServerAddress), _config.ServerPort);
                    var timeoutTask = Task.Delay(_config.ConnectTimeoutMs);
                    
                    if (await Task.WhenAny(connectTask, timeoutTask) == timeoutTask)
                    {
                        throw new TimeoutException("连接超时");
                    }
                    
                    lock (_lock)
                    {
                        _isConnected = true;
                        _reconnectAttempts = 0;
                    }
                    
                    _callback?.OnSocketStateChanged(true);
                    _callback?.OnSocketMessageReceived("Socket连接成功");
                    
                    // 启动数据接收循环
                    _ = Task.Run(() => ReceiveDataAsync(_cancellationTokenSource.Token));
                    
                    // 发送初始消息
                    await SendMessageAsync("客户端连接成功");
                    
                    return true;
                }
                catch (Exception ex)
                {
                    _callback?.OnSocketError($"连接失败 (第{attempt + 1}次): {ex.Message}");
                    
                    _tcpClient?.Dispose();
                    _tcpClient = null;
                    
                    if (attempt < _config.MaxReconnectAttempts)
                    {
                        await Task.Delay(_config.ReconnectDelayMs);
                    }
                }
            }
            
            lock (_lock)
            {
                _isConnected = false;
            }
            _callback?.OnSocketStateChanged(false);
            return false;
        }
        
        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            try
            {
                if (!_isConnected)
                {
                    _callback?.OnSocketMessageReceived("Socket未连接");
                    return;
                }
                
                _callback?.OnSocketMessageReceived("正在断开Socket连接");
                
                // 取消数据接收任务
                _cancellationTokenSource?.Cancel();
                
                // 关闭TCP连接
                _tcpClient?.Close();
                _tcpClient?.Dispose();
                _tcpClient = null;
                
                _cancellationTokenSource?.Dispose();
                _cancellationTokenSource = null;
                
                _isConnected = false;
                _callback?.OnSocketStateChanged(false);
                _callback?.OnSocketMessageReceived("Socket连接已断开");
            }
            catch (Exception ex)
            {
                _callback?.OnSocketError($"断开连接出错: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message">要发送的消息</param>
        /// <returns>发送任务</returns>
        public async Task<bool> SendMessageAsync(string message)
        {
            try
            {
                if (!_isConnected || _tcpClient?.Connected != true)
                {
                    _callback?.OnSocketError("Socket未连接，无法发送消息");
                    return false;
                }
                
                var data = Encoding.UTF8.GetBytes(message);
                var stream = _tcpClient.GetStream();
                await stream.WriteAsync(data, 0, data.Length);
                
                _callback?.OnSocketMessageReceived($"发送消息: {message}");
                return true;
            }
            catch (Exception ex)
            {
                _callback?.OnSocketError($"发送消息错误: {ex.Message}");
                return false;
            }
        }
        
        /// <summary>
        /// 异步接收数据
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        private async Task ReceiveDataAsync(CancellationToken cancellationToken)
        {
            var buffer = new byte[_config.BufferSize];
            
            while (_isConnected && _tcpClient?.Connected == true && !cancellationToken.IsCancellationRequested)
            {
                try
                {
                    var stream = _tcpClient.GetStream();
                    
                    // 设置接收超时
                    using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                    timeoutCts.CancelAfter(_config.ReceiveTimeoutMs);
                    
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, timeoutCts.Token);
                    
                    if (bytesRead > 0)
                    {
                        string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                        _callback?.OnSocketMessageReceived($"收到服务器消息: {message}");
                    }
                    else
                    {
                        // 服务器关闭连接
                        break;
                    }
                }
                catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
                {
                    // 正常取消，不报错
                    break;
                }
                catch (OperationCanceledException)
                {
                    // 接收超时，尝试重连
                    _callback?.OnSocketError("接收数据超时，尝试重连");
                    _ = Task.Run(() => ReconnectAsync());
                    break;
                }
                catch (Exception ex)
                {
                    _callback?.OnSocketError($"接收数据错误: {ex.Message}");
                    break;
                }
            }
            
            // 连接已断开
            if (_isConnected)
            {
                lock (_lock)
                {
                    _isConnected = false;
                }
                _callback?.OnSocketStateChanged(false);
                _callback?.OnSocketMessageReceived("Socket连接已断开");
            }
        }
        
        /// <summary>
        /// 自动重连
        /// </summary>
        private async Task ReconnectAsync()
        {
            lock (_lock)
            {
                if (!_isConnected)
                    return; // 已经断开或正在重连
                    
                _isConnected = false;
            }
            
            _callback?.OnSocketStateChanged(false);
            
            // 等待一段时间再重连
            await Task.Delay(_config.ReconnectDelayMs);
            
            // 尝试重连
            await ConnectWithRetryAsync();
        }
        
        /// <summary>
        /// 获取连接状态
        /// </summary>
        /// <returns>是否已连接</returns>
        public bool IsConnected => _isConnected;
        
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Disconnect();
        }
    }
}